#ifndef MAIN_WIDGET_H
#define MAIN_WIDGET_H

#include <QWidget>
#include <QColor>
#include <QPainter>
#include <QMutex>
#include <QPixmap>
#include <QImage>
#include <QMouseEvent>
#include <QPushButton>

#include <algorithm>

#include "engine.h"
#include "animations/start_animation.h"
#include "../images_manager.h"

using namespace anime;

class MainWidget: public QWidget, public Drawable
{
    Q_OBJECT

public:
    MainWidget(Engine* _engine, QMutex* _draw_mutex, QWidget* parent = 0)
        :QWidget(parent, Qt::MSWindowsFixedSizeDialogHint), back(1024, 700), content(1024, 700)
    {
        setAttribute( Qt::WA_OpaquePaintEvent );
        draw_mutex = _draw_mutex;
        content.fill(QColor(0, 0, 0, 0));
        setGeometry(30, 30, 1024, 700);
        setAttribute(Qt::WA_StaticContents);
        setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);

        back.fill(Qt::white);
        QPainter p(&back);
        QLinearGradient g(0, 768, 1024, 0);
        g.setColorAt(0, QColor(255, 0, 0, 255));
        g.setColorAt(0.3, Qt::white);
        g.setColorAt(0.7, Qt::white);
        g.setColorAt(1, QColor(250, 243, 5, 255));
        p.setBrush(QBrush(g));
        p.setPen(Qt::white);
        p.drawRect(-1, -1, 1025, 769);

        QImage* backImage = ImagesManager::GetInstance()->GetImage(ImagesManager::BACKGROUND);
        QRect target(0, 0, back.width(), back.height());
        QRect source(0, 0, backImage->width(), backImage->height());
        p.drawImage(target, *backImage, source);

        engine = _engine;

        // constructs the gui
        setMouseTracking(true);

        startAnimation = new StartAnimation(engine, 1024, 768, 1000);
        guis.push_back(startAnimation);
        startAnimation->Start();
    }

    ~MainWidget()
    {
        DeleteGuis();
    }

    QSize sizeHint() const
    {
        QSize s(1024, 768);
        return s;
    }

    void paintEvent(QPaintEvent *event)
    {
        // freezes state to perform the drawing operations
        draw_mutex->lock();

        clock_t t_paint_start = clock();

        content_painter.begin( &content );
        content_painter.drawPixmap(0, 0, back, 0, 0, back.width(), back.height());

        // draws the window content over an offscreen pixmap
        for(vector<GuiBase*>::iterator i = guis.begin(); i!=guis.end(); ++i)
        {
            (*i)->Draw(content_painter);
            (*i)->DoQWidgetOperations();
        }
        clock_t paint_time = clock() - t_paint_start;

        // uncomment the following two lines to paint the frame rate on the screen
        content_painter.setPen( QColor(0, 0, 0, 255 ) );
        content_painter.drawText(10, height() - 70, "FPS: " +
                                 QString::number( 1000/(engine->frame_time + paint_time) ) );
        content_painter.drawText( 10, height() - 50, "Frame time: " + QString::number( engine->frame_time ) + " ms");
        content_painter.drawText( 10, height() - 30, "Painting time: " + QString::number( paint_time ) + " ms");

        content_painter.end();

        // makes the pixmap visible
        QPainter painter(this);
        painter.drawPixmap(0, 0, width(), height(), content);

        // unlocks the state
        draw_mutex->unlock();
    }

    void Draw(){
        update();
    }

    void mousePressEvent(QMouseEvent* event)
    {
        event->accept();
        for(vector<GuiBase*>::iterator i=guis.begin(); i!=guis.end(); ++i)
        {
            (*i)->MousePressed(event);
        }
    }

    void mouseReleaseEvent(QMouseEvent* event)
    {
        event->accept();
        for(vector<GuiBase*>::iterator i=guis.begin(); i!=guis.end(); ++i)
        {
            (*i)->MouseReleased(event);
        }
    }

    void mouseMoveEvent(QMouseEvent* event)
    {
        event->accept();
        for(vector<GuiBase*>::iterator i=guis.begin(); i!=guis.end(); ++i)
        {
            if((*i)->mouseTracking)
                (*i)->MouseMoved(event);
        }
    }

    void AddGui(GuiBase* gui)
    {
        guis.push_back(gui);
    }

    void ClearGuis()
    {
        guis.clear();
    }

    void DeleteGuis()
    {
        for(vector<GuiBase*>::iterator i=guis.begin(); i!= guis.end(); ++i)
        {
            delete (*i);
        }
    }

    void DeleteGui(GuiBase* gui)
    {
        vector< GuiBase* >::iterator i = std::find(guis.begin(), guis.end(), gui);
        if (i != guis.end()) delete (*i);
    }

    void RemoveGui(GuiBase* gui)
    {
        vector< GuiBase* >::iterator i = std::find(guis.begin(), guis.end(), gui);
        if (i != guis.end()) guis.erase(i);
    }

private:
    QPixmap back;
    QPixmap content;
    QPainter content_painter;
    Engine* engine;
    vector<GuiBase*> guis;
    StartAnimation* startAnimation;
    QMutex* draw_mutex;
};

#endif // MAIN_WIDGET_H
